#include "GamePlayState.h"

#include "SGD Wrappers/CSGD_Direct3D.h"
#include "SGD Wrappers/CSGD_DirectInput.h"
#include "SGD Wrappers/CSGD_TextureManager.h"
#include "SGD Wrappers/CSGD_XAudio2.h"
#include "MessageSystem.h"
#include "AnimationSystem.h"
#include "EventSystem.h"

// Messages
#include "CreateProjectileMessage.h"
#include "DestroyEntityMessage.h"

#include "Emitter.h"
#include "Particle.h"

// Enemies for Testing
#include "BackstabBot.h"
#include "RepairBot.h"
#include "SapperBot.h"
#include "SwarmBot.h"
#include "SwarmBot.h"
#include "TankBot.h"
#include "TurretBot.h"
#include "OptionsState.h"

// Main menu and game
#include "Game.h"
#include "MainMenuState.h"

// Projectile
#include "Projectile.h"

// Tiny xml
#include "tinyxml.h"

GamePlayState::GamePlayState() 
{
	// Some test vals
	x = y = 10;
	sound = -1;

	player = nullptr;

	// Wrapper/Managers
	om = nullptr;

	// paused false
	paused = false;
	
	// bitmap font invalid
	FontImageID = -1;
}

GamePlayState::~GamePlayState()
{
}

GamePlayState* GamePlayState::GetInstance() 
{
	static GamePlayState instance;
	return &instance;
}

void GamePlayState::Enter()
{
	MessageSystem::GetInstance()->InitMessageSystem(&MessageProc);

	// pause to false
	paused = false;

	sound = CSGD_XAudio2::GetInstance()->MusicLoadSong(_T("sound/abandonedutopia.xwm"));

	om = ObjectManager::GetInstance();

	Animation* tmp = new Animation;
	tmp->LoadAnimationFromFile("Animation.xml", 1);
	int id = AnimationSystem::GetInstance()->AddAnimation(tmp);

	player = new Player();
	player->SetAnimationID(id);
	om->AddObject(player);

	// Test Enemies
	Enemy* backstab = new BackstabBot();
    BackstabBot* stab = dynamic_cast<BackstabBot*>(backstab);
	stab->SetAnimationID(id);
	enemies.push_back(backstab);
	om->AddObject(backstab);

	Enemy* repair = new RepairBot();
	enemies.push_back(repair);
	om->AddObject(repair);

	Enemy* sapper = new SapperBot();
	enemies.push_back(sapper);
	om->AddObject(sapper);

	Enemy* swarm = new SwarmBot();
	enemies.push_back(swarm);
	om->AddObject(swarm);

	Enemy* tank = new TankBot();
	enemies.push_back(tank);
	om->AddObject(tank);

	Enemy* turret = new TurretBot();
	enemies.push_back(turret);
	om->AddObject(turret);

	// Getting bitmap font
	GroupFont =	CBitmapFont::GetInstance();

	// Load bitmap font
	FontImageID = CSGD_TextureManager::GetInstance()->LoadTexture(_T("Graphics/Robovox.bmp"), D3DCOLOR_XRGB(0,0,0));

	// Set the bitmap font's values
	GroupFont->SetValues(32, 32, 16, 14, ' ', FontImageID);

	e = Emitter::LoadEmitter("Emitters/test.xml");

	// Sound information
	musicVolume = MainMenuState::GetInstance()->GetMusicVolume();
	SFXVolume = MainMenuState::GetInstance()->GetSFXVolume();

	// options menu
	optionsON = false;

	// Cursor position
	cursorY = 150;
	cursorX = 640;
}

void GamePlayState::Exit()
{
	// Unload bitmap font
	if(FontImageID != -1)
	{
		CSGD_TextureManager::GetInstance()->UnloadTexture(FontImageID);
		FontImageID = -1;
	}

	if( sound != -1 )
	{
		if( CSGD_XAudio2::GetInstance()->MusicIsSongPlaying(sound) )
			CSGD_XAudio2::GetInstance()->MusicStopSong(sound);

		CSGD_XAudio2::GetInstance()->MusicUnloadSong(sound);

		sound = -1;
	}

	// Release all the objects in the Object Manager
	if(om != nullptr )
	{
		om->RemoveAllObjects();
		om = nullptr;
	}

	// Delete Player
	delete player;

	//for(int i = 0; i < (int)enemies.size(); i++)
	//{
		//delete enemies[i];
		//enemies.erase(enemies.begin() + i);
	//}

	// pause to false
	paused = false;

	e->Shutdown();

	MainMenuState::GetInstance()->SetMusicVolume(musicVolume);
	MainMenuState::GetInstance()->SetSFXVolume(SFXVolume);
	SaveSounds("SoundData.xml");

	// options menu
	optionsON = false;
}

bool GamePlayState::Input()
{
	// Get Direct Input
	CSGD_DirectInput* di = CSGD_DirectInput::GetInstance();

	//if(di->JoystickButtonPressed(0) && paused == false)
	//{
	//	 Post a CreateBulletMessage
	//	CreateProjectileMessage* pMsg = new CreateProjectileMessage(this);
	//	MessageSystem::GetInstance()->SendMsg(pMsg);
	//	pMsg = nullptr;
	//}

	// Toggle sound
	if( di->KeyPressed( DIK_RETURN ) && sound != -1 && paused == false )
	{
		if( !CSGD_XAudio2::GetInstance()->MusicIsSongPlaying(sound) )
			CSGD_XAudio2::GetInstance()->MusicPlaySong(sound,true);
		else
			CSGD_XAudio2::GetInstance()->MusicStopSong(sound);

		e->Burst();
	}

	// Two bools to decide if it goes to exit or enters full screen
	bool ex = paused;
	bool full = optionsON;

	// Pause when escape is pressed
	if(optionsON == false && (di->KeyPressed(DIK_ESCAPE) || di->JoystickButtonPressed(7)) && paused == false)
	{
		paused = true;
		pauseY = 150;
	}

	// When on pause go to quit
	if(optionsON == false && (di->KeyPressed(DIK_ESCAPE) || di->JoystickButtonPressed(6)) && paused == true && ex == true)
	{
		pauseY = 350;
	}

	// Move pause menu up
	if(optionsON == false && paused == true && (di->KeyPressed(DIK_UP) || di->JoystickGetLStickDirPressed(DIR_UP)) && pauseY != 150)
		pauseY -= 100;
	else if(optionsON == false && paused == true && (di->KeyPressed(DIK_UP) || di->JoystickGetLStickDirPressed(DIR_UP)) && pauseY == 150)
		pauseY = 350;

	// Move pause menu down
	if(optionsON == false && paused == true && (di->KeyPressed(DIK_DOWN) || di->JoystickGetLStickDirPressed(DIR_DOWN)) && pauseY != 350)
		pauseY += 100;
	else if(optionsON == false && paused == true && (di->KeyPressed(DIK_DOWN) || di->JoystickGetLStickDirPressed(DIR_DOWN)) && pauseY == 350)
		pauseY = 150;

	// Return to the game if the user resumes from the pause menu
	if(optionsON == false && pauseY == 150 && (di->KeyPressed(DIK_RETURN) || di->JoystickButtonPressed(0)) && paused == true)
		paused = false;

	// Show the options if on options
	if(optionsON == false && pauseY == 250 && (di->KeyPressed(DIK_RETURN) || di->JoystickButtonPressed(0)) && paused == true)
	{
		optionsON = true;
	}

	// Return to main menu if the user quits from the pause menu
	if(optionsON == false && pauseY == 350 && (di->KeyPressed(DIK_RETURN) || di->JoystickButtonPressed(0)) && paused == true)
		Game::GetInstance()->ChangeState(MainMenuState::GetInstance());

	// If options is on do its input
	if(optionsON == true)
	{
		// If escape return to main menu
		if(CSGD_DirectInput::GetInstance()->KeyPressed(DIK_ESCAPE) ||CSGD_DirectInput::GetInstance()->JoystickButtonPressed(6))
			cursorY = 450;

		// Move cursor up
		if((CSGD_DirectInput::GetInstance()->KeyPressed(DIK_UP) || CSGD_DirectInput::GetInstance()->JoystickGetLStickDirPressed(DIR_UP)) && cursorY != 150)
			cursorY -= 100;
		else if((CSGD_DirectInput::GetInstance()->KeyPressed(DIK_UP) || CSGD_DirectInput::GetInstance()->JoystickGetLStickDirPressed(DIR_UP)) && cursorY == 150)
			cursorY = 450;

		// Move cursor down
		if((CSGD_DirectInput::GetInstance()->KeyPressed(DIK_DOWN) || CSGD_DirectInput::GetInstance()->JoystickGetLStickDirPressed(DIR_DOWN)) && cursorY != 450)
			cursorY += 100;
		else if((CSGD_DirectInput::GetInstance()->KeyPressed(DIK_DOWN) || CSGD_DirectInput::GetInstance()->JoystickGetLStickDirPressed(DIR_DOWN)) && cursorY == 450)
			cursorY = 150;

		// Move cursor left or right, if on full screen option
		if((CSGD_DirectInput::GetInstance()->KeyPressed(DIK_RIGHT) || CSGD_DirectInput::GetInstance()->JoystickGetLStickDirPressed(DIR_RIGHT)) && cursorY == 150 && cursorX != 740)
			cursorX += 100;
		else if((CSGD_DirectInput::GetInstance()->KeyPressed(DIK_RIGHT) || CSGD_DirectInput::GetInstance()->JoystickGetLStickDirPressed(DIR_RIGHT)) && cursorY == 150 && cursorX == 740)
			cursorX = 640;
		if((CSGD_DirectInput::GetInstance()->KeyPressed(DIK_LEFT) || CSGD_DirectInput::GetInstance()->JoystickGetLStickDirPressed(DIR_LEFT)) && cursorY == 150 && cursorX != 640)
			cursorX -= 100;
		else if((CSGD_DirectInput::GetInstance()->KeyPressed(DIK_LEFT) || CSGD_DirectInput::GetInstance()->JoystickGetLStickDirPressed(DIR_LEFT)) && cursorY == 150 && cursorX == 640)
			cursorX = 740;

		// Change full screen
		if(full == true && optionsON == true && (CSGD_DirectInput::GetInstance()->KeyPressed(DIK_RETURN) || CSGD_DirectInput::GetInstance()->JoystickButtonPressed(0)) && cursorY == 150 && cursorX == 640)
		{
			Game::GetInstance()->SetFullScreen(false);
			Game::GetInstance()->FullScreenOn();
		}
		else if(full == true && optionsON == true && (CSGD_DirectInput::GetInstance()->KeyPressed(DIK_RETURN) || CSGD_DirectInput::GetInstance()->JoystickButtonPressed(0)) && cursorY == 150 && cursorX == 740)
		{
			Game::GetInstance()->SetFullScreen(true);
			Game::GetInstance()->FullScreenOn();
		}

		// Change music
		if(cursorY == 250 && (CSGD_DirectInput::GetInstance()->KeyDown(DIK_RIGHT) || CSGD_DirectInput::GetInstance()->JoystickGetLStickDirDown(DIR_RIGHT)) && musicVolume <= 99)
		{
			soundTimer += 0.005;
			if(soundTimer >= 1)
			{
				musicVolume += 1;
				soundTimer = 0;
				CSGD_XAudio2::GetInstance()->MusicSetMasterVolume((float)(musicVolume/100.0f));
			}
		}
		if(cursorY == 250 && (CSGD_DirectInput::GetInstance()->KeyDown(DIK_LEFT) || CSGD_DirectInput::GetInstance()->JoystickGetLStickDirDown(DIR_LEFT)) && musicVolume >= 1)
		{
			soundTimer += 0.005;
			if(soundTimer >= 1)
			{
				musicVolume -= 1;
				soundTimer = 0;
				CSGD_XAudio2::GetInstance()->MusicSetMasterVolume((float)(musicVolume/100.0f));
			}
		}

		// Change SFX
		if(cursorY == 350 && (CSGD_DirectInput::GetInstance()->KeyDown(DIK_RIGHT) || CSGD_DirectInput::GetInstance()->JoystickGetLStickDirDown(DIR_RIGHT)) && SFXVolume <= 99)
		{
			soundTimer += 0.005;
			if(soundTimer >= 1)
			{
				SFXVolume += 1;
				soundTimer = 0;
				CSGD_XAudio2::GetInstance()->SFXSetMasterVolume((float)(SFXVolume/100.0f));
			}
		}
		if(cursorY == 350 && (CSGD_DirectInput::GetInstance()->KeyDown(DIK_LEFT) || CSGD_DirectInput::GetInstance()->JoystickGetLStickDirDown(DIR_LEFT)) && SFXVolume >= 1)
		{
			soundTimer += 0.005;
			if(soundTimer >= 1)
			{
				SFXVolume -= 1;
				soundTimer = 0;
				CSGD_XAudio2::GetInstance()->SFXSetMasterVolume((float)(SFXVolume/100.0f));
			}
		}

		// Go back to the pause menu
		if((CSGD_DirectInput::GetInstance()->KeyPressed(DIK_RETURN) || CSGD_DirectInput::GetInstance()->JoystickButtonPressed(0)) && cursorY == 450)
		{
			optionsON = false;
		}
	}

	return true;

}

void GamePlayState::Update(float elapsed)
{
	if(!paused)
	{
		om->UpdateAll(elapsed);
		om->CheckCollisions();
		MessageSystem::GetInstance()->ProcessMessages();
		EventSystem::GetInstance()->ProcessEvents();
		e->Update(elapsed);
	}
}

void GamePlayState::Render()
{
	// Selected and not selected colors
	DWORD isSelected = D3DCOLOR_ARGB(255,255,0,0);
	DWORD notSelected =  D3DCOLOR_ARGB(255,0,255,255);

	e->Render();

	om->RenderAll();

	// Draw pause menu
	if(paused == true && optionsON == false)
	{
		GroupFont->Print("Paused", 32, 32, 3.0f, D3DCOLOR_ARGB(255,0,255,255));
		GroupFont->Print("Resume", Game::GetInstance()->GetScreenWidth()/2, 150, pauseY==150 ? 2.0f : 1.0f, pauseY==150 ? isSelected : notSelected);
		GroupFont->Print("Options", Game::GetInstance()->GetScreenWidth()/2, 250, pauseY==250 ? 2.0f : 1.0f, pauseY==250 ? isSelected : notSelected);
		GroupFont->Print("Quit", Game::GetInstance()->GetScreenWidth()/2, 350, pauseY==350 ? 2.0f : 1.0f, pauseY==350 ? isSelected : notSelected);
	}

	// Draw the hud (not the final version this just shows false health and energy)
	GroupFont->Print("Health:", 32, 580, 1.0f, D3DCOLOR_ARGB(255,0,255,255));
	GroupFont->Print("100", 210, 580, 1.0f, D3DCOLOR_ARGB(255,0,255,255));
	GroupFont->Print("Energy:", 500, 580, 1.0f, D3DCOLOR_ARGB(255,0,255,255));
	GroupFont->Print("100", 678, 580, 1.0f, D3DCOLOR_ARGB(255,0,255,255));

	// Draw the options
	if(optionsON == true)
	{
		// Flush sprites	
		CSGD_Direct3D::GetInstance()->GetSprite()->Flush();

		// Position of music and sfx on the screen
		int musicPosition = 500+musicVolume*3;
		int SFXPositon = 500+SFXVolume*3;

		// Selected and not selected colors
		DWORD isSelected = D3DCOLOR_ARGB(255,255,0,0);
		DWORD notSelected =  D3DCOLOR_ARGB(255,0,255,255);

		// Title of options
		GroupFont->Print("Options", 32, 32, 3.0f, D3DCOLOR_ARGB(255,0,255,255));

		// Options menu
		GroupFont->Print("Full Screen: ", 340-100, 150,1.0f, notSelected);
		GroupFont->Print("On", 640-100, 150, 1.0f, cursorY==150 && cursorX==640 ? isSelected : notSelected);
		GroupFont->Print("Off", 740-100, 150, 1.0f, cursorY==150 && cursorX==740 ? isSelected : notSelected);
		GroupFont->Print("Music:", 340-100, 250, 1.0f, cursorY==250 ? isSelected : notSelected);
		GroupFont->Print("SFX:", 340-100, 350, 1.0f, cursorY==350 ? isSelected : notSelected);
		GroupFont->Print("Back", 340-100, 450, 1.0f, cursorY==450 ? isSelected : notSelected);

		// Draw lines and box for music and sfx
		RECT musicBox;
		musicBox.left = musicPosition-10-100;
		musicBox.right = musicPosition+10-100;
		musicBox.top = 240;
		musicBox.bottom = 260;
		RECT SFXBox;
		SFXBox.left = SFXPositon-10-100;
		SFXBox.right = SFXPositon+10-100;
		SFXBox.top = 340;
		SFXBox.bottom = 360;
		CSGD_Direct3D::GetInstance()->DrawLine(500-100,250,800-100,250,0,255,255);
		CSGD_Direct3D::GetInstance()->DrawLine(500-100,350,800-100,350,0,255,255);
		CSGD_Direct3D::GetInstance()->DrawRect(musicBox, cursorY==250 ? 255 : 0, cursorY==250 ? 0 : 255, cursorY==250 ? 0 : 255);
		CSGD_Direct3D::GetInstance()->DrawRect(SFXBox, cursorY==350 ? 255 : 0, cursorY==350 ? 0 : 255, cursorY==350 ? 0 : 255);
	}
}

void GamePlayState::MessageProc(Message* msg)
{
	GamePlayState* self = GamePlayState::GetInstance();

	switch(msg->GetMessageID())
	{
	case MSG_CREATE_PROJECTILE:
		{
			Entity* owner = dynamic_cast<CreateProjectileMessage*>(msg)->GetOwner();

			if(owner != nullptr)
			{
				switch(dynamic_cast<CreateProjectileMessage*>(msg)->GetBulletType())
				{
				case BASIC:
					{
						Projectile* proj = new Projectile();

						proj->SetX(owner->GetX());
						proj->SetY(owner->GetY());
						proj->SetBulletType(dynamic_cast<CreateProjectileMessage*>(msg)->GetBulletType());
						proj->SetTextureID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Graphics/Dummy Images/laserShot.png")));
						proj->SetWidth(16);
						proj->SetHeight(8);
						proj->SetMoveSpeed(500.0f);
						proj->SetDamage(20.0f);
						proj->SetOwner(owner);

						self->om->AddObject(proj);
					}
					break;

				case ROCKET:
					break;

				case EMP:
					break;
				}
			}
		}
		break;

	case MSG_DESTROY_ENTITY:
		{

			Entity* entity = dynamic_cast<DestroyEntityMessage*>(msg)->GetEntity();

			// Remove the object from the Object Manager
			self->om->RemoveObject(entity);
		}
		break;
	}
}

void GamePlayState::SaveSounds(const char* szFileName)
{
	// Create a TinyXML Document
	TiXmlDocument doc;

	// Create a TinyXML Declaration (version info)
	TiXmlDeclaration* pDec = new TiXmlDeclaration("1.0","utf-8","");
	// Add the declaration to the document
	doc.LinkEndChild(pDec);
	
	// Create a root node for the document (sound_list)
	TiXmlElement* pRoot = new TiXmlElement("sound_list");
	// Add the root node to the document
	doc.LinkEndChild(pRoot);

	// Create a node for the sounds
	TiXmlElement* pSound = new TiXmlElement("sound_info");

	// Fill the node with sounds info
	pSound->SetAttribute("music",musicVolume);
	pSound->SetAttribute("sfx",SFXVolume);

	// Add the sounds node to the "sounds_list"
	pRoot->LinkEndChild(pSound);

	// Save the XML document to the file
	doc.SaveFile(szFileName);
}